<?php
require_once 'Zend/Db/Table/Abstract.php';

class PasswordResetAuthorization extends Zend_Db_Table_Abstract {
	
	const FREE_TO_USE = 0;
	const VISITED = 1;
	const EXPIRED = 2;
	const MAX_TRY_TIMES = 10;
	
	protected $_name = 'password_reset_authorization';
	protected $_primary = 'id';
	
	protected $_referenceMap = array(
		'User' => array (
			'columns' => 'user_id',
			'refTableClass' => 'User',
			'refColumns' => 'id'
		)
	);
	
	/**
	 * Add or update authorization key that will used by given user.
	 * There is only one FREE_TO_USE key for one user,
	 * if there is already exist such key, then just return this key,
	 * otherwise, add key to table.
	 * 
	 * If the generated key is already exist, then try to generate a new one,
	 * if try it 10 times, still find the existed one, then abort it.
	 * @param $user
	 * @param $created
	 * @return return created/found authorization instance
	 */
	public static function addOrUpdateKey($user, $created) {
		$object = new PasswordResetAuthorization();
		$select = $object->select()
		->where('user_id = ?', $user->id)
		->where('status = ?', self::FREE_TO_USE);
		$instance = $object->fetchRow($select);
		if (isset($instance)) {
			return $instance;
		} else {
			$tryTimes = 0;
			$key = $object->generateKey($user->email);
			$instance = self::findByKey($key);
			while (isset($instance) && $tryTimes < self::MAX_TRY_TIMES) {
				$key = $object->generateKey($user->email);
				$instance = self::findByKey($key);
				$tryTimes++;
			}
			if ($tryTimes <= self::MAX_TRY_TIMES) {
				$data = array(
					'user_id' => $user->id,
					'key' => $key,
					'status' => self::FREE_TO_USE,
					'created' => $created
				);
				$id = $object->insert($data);
			} else {
				throw new Exception('Failed to generate unique key for password reset, please try it later.');
			}
			return $object->findById($id);
		}
	}
	
	/**
	 * Update key status to visited, once user has tried to reset their password,
	 * via the reset url.
	 * 
	 * @param $key
	 */
	public static function updateStatusToVisited($key) {
		$instance = self::findByKey($key);
		if (isset($instance)) {
			$instance->status = self::VISITED;
			$instance->save();
		}
	}
	
	private function findById($id) {
		$object = new PasswordResetAuthorization();
		return $object->find($id)->current();
	}
	
	/**
	 * Find password reset authorization key.
	 * 
	 * @param $key
	 * @return return instance if given key is found, otherwise, return null
	 */
	public static function findByKey($key) {
		$object = new PasswordResetAuthorization();
		$select = $object->select()->where('`key` = ?', $key);
		return $object->fetchRow($select);
	}
	
	/**
	 * Generate key.
	 * 
	 * @param $email
	 */
	private function generateKey($email) {
		$seed = $email.time();
		return md5($seed);
	}
}
?>